package org.sdnstproject.interlayer.OF10Protocal;

import java.util.Arrays;
import java.util.Random;

import org.projectfloodlight.openflow.types.U16;
import org.projectfloodlight.openflow.types.U32;
import org.sdnstproject.interlayer.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class FuFlowModV10 {
	private static final Logger log = LoggerFactory.getLogger(FuFlowModV10.class);
    public byte version = (byte)1;
    public byte type = (byte)14;
    public short length = (short)72;//MINIMUM_LENGTH = 72;
    public long xid = 0x0;
    public byte[] match = Utils.hexStringToByteArray("000100268000000400000002800006060ae8bf550be5800008069a089f9ea63080000a0208060000");
    public long cookie = 0x0020000003000000L;//U64
    public short command = 1;
    public int idleTimeout = 0x5;
    public int hardTimeout = 0x0;
    public int priority = 0x1;
    public int bufferId = 0xffffffff;//OFBufferId
    public int outPort = 0xffffffff;//OFPort
    /*public enum OFFlowModFlags {
     SEND_FLOW_REM:(short) 0x1,
     CHECK_OVERLAP:(short) 0x2,
     EMERG,
     RESET_COUNTS:(short) 0x4,
     NO_PKT_COUNTS:(short) 0x8,
     NO_BYT_COUNTS:(short) 0x10,
     BSN_SEND_IDLE:(short) 0x80;
	}* */
    public int flags = 0x0;//Set<OFFlowModFlags>
    public long actions;
    
	public FuFlowModV10() {
			
	}
	
	public FuFlowModV10 setXid(long xid) {
		this.xid = xid;
		return this;
	}
	
	private byte[] commands = new byte[] {0,1,2,3,4};
    public FuFlowModV10 setField(String field, String value) {
		switch (field) {
		case "version":
			this.version = Byte.parseByte(value);
			break;
		case "type":
			this.type = Byte.parseByte(value);
			break;
		case "length":
			this.length = Short.parseShort(value);
			break;
		case "xid":
			this.xid = Long.parseLong(value);
			break;
		case "match":
			this.match = new byte[(new Random().nextInt(5)+1)*8+4];
			new Random().nextBytes(match);
			break;
		case "cookie":
			this.cookie = Long.parseLong(value);
			break;
		case "command":
			if(value.equals("random")) {
				this.command = commands[new Random().nextInt(5)];
				break;
			}
			this.command = Short.parseShort(value);
			break;
		case "idleTimeout":
			this.idleTimeout = Integer.parseInt(value);
			break;
		case "hardTimeout":
			this.hardTimeout = Integer.parseInt(value);
			break;
		case "priority":
			this.priority = Integer.parseInt(value);
			break;
		case "bufferId":
			this.bufferId = Integer.parseInt(value);
			break;
		case "outPort":
			this.outPort = Integer.parseInt(value);
		case "flags":
			this.flags = Integer.parseInt(value);
			break;
		case "actions":
			this.actions = Long.parseLong(value);
			break;
		}
		return this;
	}
    
    public ByteBuf writeTo() {
		ByteBuf bb = Unpooled.directBuffer();
		int startIndex = bb.writerIndex();
        // fixed value property version = 1
        bb.writeByte((byte) 0x1);
        // fixed value property type = 14
        bb.writeByte((byte) 0xe);
        // length is length of variable message, will be updated at the end
        int lengthIndex = bb.writerIndex();
        bb.writeShort(length);

        bb.writeInt(U32.t(xid));
        bb.writeBytes(match);
        bb.writeLong(cookie);
        // fixed value property command = 1
        bb.writeShort(command);
        bb.writeShort((short) 0x1);
        bb.writeShort(U16.t(idleTimeout));
        bb.writeShort(U16.t(hardTimeout));
        bb.writeShort(U16.t(priority));
        bb.writeInt(bufferId);
        bb.writeShort(U16.t(outPort));
        bb.writeShort(U16.t(flags));
        bb.writeInt(U32.t(actions));

        // update length field
        length = (short)(bb.writerIndex() - startIndex);
        bb.setShort(lengthIndex, length);
        return bb;
    }
    
    @Override
    public String toString() {
        StringBuilder b = new StringBuilder("OFFlowModVer10(");
        b.append("version=").append(version);
        b.append(", ");
        b.append("type=").append(type);
        b.append(", ");
        b.append("length=").append(length);
        b.append(", ");
        b.append("xid=").append(xid);
        b.append(", ");
        b.append("match=").append(Arrays.toString(match));
        b.append(", ");
        b.append("cookie=").append(cookie);
        b.append(", ");
        b.append("command=").append(command);
        b.append(", ");
        b.append("idleTimeout=").append(idleTimeout);
        b.append(", ");
        b.append("hardTimeout=").append(hardTimeout);
        b.append(", ");
        b.append("priority=").append(priority);
        b.append(", ");
        b.append("bufferId=").append(bufferId);
        b.append(", ");
        b.append("outPort=").append(outPort);
        b.append(", ");
        b.append("flags=").append(flags);
        b.append(", ");
        b.append("actions=").append(actions);
        b.append(")");
        return b.toString();
    }
    
}
